home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-19 / gpt32src.zip / SETSHOW.C < prev    next >
C/C++ Source or Header  |  1992-03-25  |  67KB  |  2,619 lines

  1. #ifndef lint
  2. static char *RCSid = "$Id: setshow.c,v 3.26 92/03/24 22:34:20 woo Exp Locker: woo $";
  3. #endif
  4.  
  5. /* GNUPLOT - setshow.c */
  6. /*
  7.  * Copyright (C) 1986, 1987, 1990, 1991, 1992   Thomas Williams, Colin Kelley
  8.  *
  9.  * Permission to use, copy, and distribute this software and its
  10.  * documentation for any purpose with or without fee is hereby granted, 
  11.  * provided that the above copyright notice appear in all copies and 
  12.  * that both that copyright notice and this permission notice appear 
  13.  * in supporting documentation.
  14.  *
  15.  * Permission to modify the software is granted, but not the right to
  16.  * distribute the modified code.  Modifications are to be distributed 
  17.  * as patches to released version.
  18.  *  
  19.  * This software is provided "as is" without express or implied warranty.
  20.  * 
  21.  *
  22.  * AUTHORS
  23.  * 
  24.  *   Original Software:
  25.  *     Thomas Williams,  Colin Kelley.
  26.  * 
  27.  *   Gnuplot 2.0 additions:
  28.  *       Russell Lang, Dave Kotz, John Campbell.
  29.  *
  30.  *   Gnuplot 3.0 additions:
  31.  *       Gershon Elber and many others.
  32.  * 
  33.  * Send your comments or suggestions to 
  34.  *  info-gnuplot@ames.arc.nasa.gov.
  35.  * This is a mailing list; to join it send a note to 
  36.  *  info-gnuplot-request@ames.arc.nasa.gov.  
  37.  * Send bug reports to
  38.  *  bug-gnuplot@ames.arc.nasa.gov.
  39.  */
  40.  
  41. #include <stdio.h>
  42. #include <math.h>
  43. #include "plot.h"
  44. #include "setshow.h"
  45.  
  46. #define DEF_FORMAT   "%g"    /* default format for tic mark labels */
  47. #define SIGNIF (0.01)        /* less than one hundredth of a tic mark */
  48.  
  49. /*
  50.  * global variables to hold status of 'set' options
  51.  *
  52.  */
  53. BOOLEAN            autoscale_r    = TRUE;
  54. BOOLEAN            autoscale_t    = TRUE;
  55. BOOLEAN            autoscale_u    = TRUE;
  56. BOOLEAN            autoscale_v    = TRUE;
  57. BOOLEAN            autoscale_x    = TRUE;
  58. BOOLEAN            autoscale_y    = TRUE;
  59. BOOLEAN            autoscale_z    = TRUE;
  60. BOOLEAN            autoscale_lt    = TRUE;
  61. BOOLEAN            autoscale_lu    = TRUE;
  62. BOOLEAN            autoscale_lv    = TRUE;
  63. BOOLEAN            autoscale_lx    = TRUE;
  64. BOOLEAN            autoscale_ly    = TRUE;
  65. BOOLEAN            autoscale_lz    = TRUE;
  66. BOOLEAN           clip_points    = FALSE;
  67. BOOLEAN           clip_lines1    = TRUE;
  68. BOOLEAN           clip_lines2    = FALSE;
  69. BOOLEAN            draw_border    = TRUE;
  70. BOOLEAN            draw_surface    = TRUE;
  71. BOOLEAN            timedate    = FALSE;
  72. char            dummy_var[MAX_NUM_VAR][MAX_ID_LEN+1] = { "x", "y" };
  73. char            xformat[MAX_ID_LEN+1] = DEF_FORMAT;
  74. char            yformat[MAX_ID_LEN+1] = DEF_FORMAT;
  75. char            zformat[MAX_ID_LEN+1] = DEF_FORMAT;
  76. enum            PLOT_STYLE data_style    = POINTS,
  77.             func_style    = LINES;
  78. BOOLEAN            grid        = FALSE;
  79. int                key            = -1;    /* default position */
  80. double            key_x, key_y, key_z;    /* user specified position for key */
  81. BOOLEAN            log_x        = FALSE,
  82.             log_y        = FALSE,
  83.             log_z        = FALSE;
  84. FILE*            outfile;
  85. char            outstr[MAX_ID_LEN+1] = "STDOUT";
  86. BOOLEAN            parametric    = FALSE;
  87. BOOLEAN            polar        = FALSE;
  88. BOOLEAN            hidden3d    = FALSE;
  89. int            angles_format    = ANGLES_RADIANS;
  90. int            mapping3d    = MAP3D_CARTESIAN;
  91. int            samples        = SAMPLES;
  92. int            iso_samples    = ISO_SAMPLES;
  93. float            xsize        = 1.0;  /* scale factor for size */
  94. float            ysize        = 1.0;  /* scale factor for size */
  95. float            zsize        = 1.0;  /* scale factor for size */
  96. float            surface_rot_z   = 30.0; /* Default 3d transform. */
  97. float            surface_rot_x   = 60.0;
  98. float            surface_scale   = 1.0;
  99. float            surface_zscale  = 1.0;
  100. int            term        = 0;        /* unknown term is 0 */
  101. char            term_options[MAX_ID_LEN+1] = "";
  102. char            title[MAX_LINE_LEN+1] = "";
  103. char            xlabel[MAX_LINE_LEN+1] = "";
  104. char            ylabel[MAX_LINE_LEN+1] = "";
  105. char            zlabel[MAX_LINE_LEN+1] = "";
  106. int            time_xoffset    = 0;
  107. int            time_yoffset    = 0;
  108. int            title_xoffset    = 0;
  109. int            title_yoffset    = 0;
  110. int            xlabel_xoffset    = 0;
  111. int            xlabel_yoffset    = 0;
  112. int            ylabel_xoffset    = 0;
  113. int            ylabel_yoffset    = 0;
  114. int            zlabel_xoffset    = 0;
  115. int            zlabel_yoffset    = 0;
  116. double            rmin        = -0.0,
  117.             rmax        =  10.0,
  118.             tmin        = -5.0,
  119.             tmax        =  5.0,
  120.             umin        = -5.0,
  121.             umax        = 5.0,
  122.             vmin        = -5.0,
  123.             vmax        = 5.0,
  124.             xmin        = -10.0,
  125.             xmax        = 10.0,
  126.             ymin        = -10.0,
  127.             ymax        = 10.0,
  128.             zmin        = -10.0,
  129.             zmax        = 10.0;
  130. double            loff        = 0.0,
  131.             roff        = 0.0,
  132.             toff        = 0.0,
  133.             boff        = 0.0;
  134. int            draw_contour    = CONTOUR_NONE;
  135. int            contour_pts    = 5;
  136. int            contour_kind    = CONTOUR_KIND_LINEAR;
  137. int            contour_order    = 4;
  138. int            contour_levels    = 5;
  139. double            zero = ZERO;            /* zero threshold, not 0! */
  140.  
  141. BOOLEAN xzeroaxis = TRUE;
  142. BOOLEAN yzeroaxis = TRUE;
  143.  
  144. BOOLEAN xtics = TRUE;
  145. BOOLEAN ytics = TRUE;
  146. BOOLEAN ztics = TRUE;
  147.  
  148. float ticslevel = 0.5;
  149.  
  150. struct ticdef xticdef = {TIC_COMPUTED};
  151. struct ticdef yticdef = {TIC_COMPUTED};
  152. struct ticdef zticdef = {TIC_COMPUTED};
  153.  
  154. BOOLEAN            tic_in        = TRUE;
  155.  
  156. struct text_label *first_label = NULL;
  157. struct arrow_def *first_arrow = NULL;
  158.  
  159. /*** other things we need *****/
  160. extern char *strcpy(),*strcat();
  161. extern int strlen();
  162. extern FILE *popen();
  163.  
  164. /* input data, parsing variables */
  165. extern struct lexical_unit token[];
  166. extern char input_line[];
  167. extern int num_tokens, c_token;
  168. extern BOOLEAN interactive;    /* from plot.c */
  169.  
  170. extern char replot_line[];
  171. extern struct udvt_entry *first_udv;
  172. extern BOOLEAN is_3d_plot;
  173.  
  174. extern double magnitude(),real();
  175. extern struct value *const_express();
  176.  
  177. /******** Local functions ********/
  178. static void set_xyzlabel();
  179. static void set_label();
  180. static void set_nolabel();
  181. static void set_arrow();
  182. static void set_noarrow();
  183. static void load_tics();
  184. static void load_tic_user();
  185. static void free_marklist();
  186. static void load_tic_series();
  187. static void load_offsets();
  188.  
  189. static void show_style(), show_range(), show_zero(), show_border();
  190. static void show_offsets(), show_output(), show_samples(), show_isosamples();
  191. static void show_view(), show_size(), show_title(), show_xlabel();
  192. static void show_angles();
  193. static void show_ylabel(), show_zlabel(), show_xzeroaxis(), show_yzeroaxis();
  194. static void show_label(), show_arrow(), show_grid(), show_key();
  195. static void show_polar(), show_parametric(), show_tics(), show_ticdef();
  196. static void show_time(), show_term(), show_plot(), show_autoscale(), show_clip();
  197. static void show_contour(), show_mapping(), show_format(), show_logscale();
  198. static void show_variables(), show_surface(), show_hidden3d();
  199. static void delete_label();
  200. static int assign_label_tag();
  201. static void delete_arrow();
  202. static int assign_arrow_tag();
  203. static BOOLEAN set_one(), set_two(), set_three();
  204. static BOOLEAN show_one(), show_two();
  205.  
  206. /******** The 'set' command ********/
  207. void
  208. set_command()
  209. {
  210.     c_token++;
  211.  
  212.     if (!set_one() && !set_two() && !set_three())
  213.     int_error(
  214.     "valid set options:  'angles' '{no}arrow', {no}autoscale', \n\
  215.     '{no}border', '{no}clip', 'cntrparam', '{no}contour', 'data style', \n\
  216.     'dummy', 'format', 'function style', '{no}grid', '{no}hidden3d', \n\
  217.     'isosamples', '{no}key', '{no}label', '{no}logscale', 'mapping', \n\
  218.     'offsets', 'output', '{no}parametric', '{no}polar', 'rrange', \n\
  219.     'samples', 'size', '{no}surface', 'terminal', 'tics', 'ticslevel', \n\
  220.     '{no}time', 'title', 'trange', 'urange', 'view', 'vrange', 'xlabel', \n\
  221.     'xrange', '{no}xtics', '{no}xzeroaxis', 'ylabel', 'yrange', \n\
  222.     '{no}ytics', '{no}yzeroaxis', 'zero', '{no}zeroaxis', 'zlabel', \n\
  223.     'zrange', '{no}ztics'", c_token);
  224. }
  225.  
  226. /* return TRUE if a command match, FALSE if not */
  227. static BOOLEAN
  228. set_one()
  229. {
  230.     if (almost_equals(c_token,"ar$row")) {
  231.         c_token++;
  232.         set_arrow();
  233.     }
  234.     else if (almost_equals(c_token,"noar$row")) {
  235.         c_token++;
  236.         set_noarrow();
  237.     }
  238.      else if (almost_equals(c_token,"au$toscale")) {
  239.         c_token++;
  240.         if (END_OF_COMMAND) {
  241.            autoscale_r=autoscale_t = autoscale_x = autoscale_y = autoscale_z = TRUE;
  242.         } else if (equals(c_token, "xy") || equals(c_token, "yx")) {
  243.            autoscale_x = autoscale_y = TRUE;
  244.            c_token++;
  245.         } else if (equals(c_token, "r")) {
  246.            autoscale_r = TRUE;
  247.            c_token++;
  248.         } else if (equals(c_token, "t")) {
  249.            autoscale_t = TRUE;
  250.            c_token++;
  251.         } else if (equals(c_token, "x")) {
  252.            autoscale_x = TRUE;
  253.            c_token++;
  254.         } else if (equals(c_token, "y")) {
  255.            autoscale_y = TRUE;
  256.            c_token++;
  257.         } else if (equals(c_token, "z")) {
  258.            autoscale_z = TRUE;
  259.            c_token++;
  260.         }
  261.     } 
  262.     else if (almost_equals(c_token,"noau$toscale")) {
  263.         c_token++;
  264.         if (END_OF_COMMAND) {
  265.            autoscale_r=autoscale_t = autoscale_x = autoscale_y = autoscale_z = FALSE;
  266.         } else if (equals(c_token, "xy") || equals(c_token, "tyx")) {
  267.            autoscale_x = autoscale_y = FALSE;
  268.            c_token++;
  269.         } else if (equals(c_token, "r")) {
  270.            autoscale_r = FALSE;
  271.            c_token++;
  272.         } else if (equals(c_token, "t")) {
  273.            autoscale_t = FALSE;
  274.            c_token++;
  275.         } else if (equals(c_token, "x")) {
  276.            autoscale_x = FALSE;
  277.            c_token++;
  278.         } else if (equals(c_token, "y")) {
  279.            autoscale_y = FALSE;
  280.            c_token++;
  281.         } else if (equals(c_token, "z")) {
  282.            autoscale_z = FALSE;
  283.            c_token++;
  284.         }
  285.     } 
  286.     else if (almost_equals(c_token,"bor$der")) {
  287.         draw_border = TRUE;
  288.         c_token++;
  289.     }
  290.     else if (almost_equals(c_token,"nobor$der")) {
  291.         draw_border = FALSE;
  292.         c_token++;
  293.     }
  294.     else if (almost_equals(c_token,"c$lip")) {
  295.         c_token++;
  296.         if (END_OF_COMMAND)
  297.          /* assuming same as points */
  298.          clip_points = TRUE;
  299.         else if (almost_equals(c_token, "p$oints"))
  300.          clip_points = TRUE;
  301.         else if (almost_equals(c_token, "o$ne"))
  302.          clip_lines1 = TRUE;
  303.         else if (almost_equals(c_token, "t$wo"))
  304.          clip_lines2 = TRUE;
  305.         else
  306.          int_error("expecting 'points', 'one', or 'two'", c_token);
  307.         c_token++;
  308.     }
  309.     else if (almost_equals(c_token,"noc$lip")) {
  310.         c_token++;
  311.         if (END_OF_COMMAND) {
  312.            /* same as all three */
  313.            clip_points = FALSE;
  314.            clip_lines1 = FALSE;
  315.            clip_lines2 = FALSE;
  316.         } else if (almost_equals(c_token, "p$oints"))
  317.          clip_points = FALSE;
  318.         else if (almost_equals(c_token, "o$ne"))
  319.          clip_lines1 = FALSE;
  320.         else if (almost_equals(c_token, "t$wo"))
  321.          clip_lines2 = FALSE;
  322.         else
  323.          int_error("expecting 'points', 'one', or 'two'", c_token);
  324.         c_token++;
  325.     }
  326.     else if (almost_equals(c_token,"hi$dden3d")) {
  327.         hidden3d = TRUE;
  328.         c_token++;
  329.     }
  330.     else if (almost_equals(c_token,"nohi$dden3d")) {
  331.         hidden3d = FALSE;
  332.         c_token++;
  333.     }
  334.     else if (almost_equals(c_token,"ma$pping3d")) {
  335.         c_token++;
  336.         if (END_OF_COMMAND)
  337.          /* assuming same as points */
  338.          mapping3d = MAP3D_CARTESIAN;
  339.         else if (almost_equals(c_token, "ca$rtesian"))
  340.          mapping3d = MAP3D_CARTESIAN;
  341.         else if (almost_equals(c_token, "s$pherical"))
  342.          mapping3d = MAP3D_SPHERICAL;
  343.         else if (almost_equals(c_token, "cy$lindrical"))
  344.          mapping3d = MAP3D_CYLINDRICAL;
  345.         else
  346.          int_error("expecting 'cartesian', 'spherical', or 'cylindrical'", c_token);
  347.         c_token++;
  348.     }
  349.     else if (almost_equals(c_token,"co$ntour")) {
  350.         c_token++;
  351.         if (END_OF_COMMAND)
  352.          /* assuming same as points */
  353.          draw_contour = CONTOUR_BASE;
  354.         else if (almost_equals(c_token, "ba$se"))
  355.          draw_contour = CONTOUR_BASE;
  356.         else if (almost_equals(c_token, "s$urface"))
  357.          draw_contour = CONTOUR_SRF;
  358.         else if (almost_equals(c_token, "bo$th"))
  359.          draw_contour = CONTOUR_BOTH;
  360.         else
  361.          int_error("expecting 'base', 'surface', or 'both'", c_token);
  362.         c_token++;
  363.     }
  364.     else if (almost_equals(c_token,"noco$ntour")) {
  365.         c_token++;
  366.         draw_contour = CONTOUR_NONE;
  367.     }
  368.     else if (almost_equals(c_token,"cntrp$aram")) {
  369.         struct value a;
  370.  
  371.         c_token++;
  372.         if (END_OF_COMMAND) {
  373.          /* assuming same as defaults */
  374.          contour_pts = 5;
  375.          contour_kind = CONTOUR_KIND_LINEAR;
  376.          contour_order = 4;
  377.          contour_levels = 5;
  378.         }
  379.         else if (almost_equals(c_token, "p$oints")) {
  380.          c_token++;
  381.          contour_pts = (int) real(const_express(&a));
  382.         }
  383.         else if (almost_equals(c_token, "li$near")) {
  384.          c_token++;
  385.          contour_kind = CONTOUR_KIND_LINEAR;
  386.         }
  387.         else if (almost_equals(c_token, "c$ubicspline")) {
  388.          c_token++;
  389.          contour_kind = CONTOUR_KIND_CUBIC_SPL;
  390.         }
  391.         else if (almost_equals(c_token, "b$spline")) {
  392.          c_token++;
  393.          contour_kind = CONTOUR_KIND_BSPLINE;
  394.         }
  395.         else if (almost_equals(c_token, "le$vels")) {
  396.          c_token++;
  397.          contour_levels = (int) real(const_express(&a));
  398.         }
  399.         else if (almost_equals(c_token, "o$rder")) {
  400.          int order;
  401.          c_token++;
  402.          order = (int) real(const_express(&a));
  403.          if ( order < 2 || order > 10 )
  404.              int_error("bspline order must be in [2..10] range.", c_token);
  405.          contour_order = order;
  406.         }
  407.         else
  408.          int_error("expecting 'linear', 'cubicspline', 'bspline', 'points', 'levels' or 'order'", c_token);
  409.         c_token++;
  410.     }
  411.     else if (almost_equals(c_token,"d$ata")) {
  412.         c_token++;
  413.         if (!almost_equals(c_token,"s$tyle"))
  414.             int_error("expecting keyword 'style'",c_token);
  415.         data_style = get_style();
  416.     }
  417.     else if (almost_equals(c_token,"d$ummy")) {
  418.         c_token++;
  419.         if (END_OF_COMMAND)
  420.             int_error("expecting dummy variable name", c_token);
  421.         else {
  422.             if (!equals(c_token,","))
  423.                 copy_str(dummy_var[0],c_token++);
  424.             if (!END_OF_COMMAND && equals(c_token,",")) {
  425.                 c_token++;
  426.                 if (END_OF_COMMAND)
  427.                     int_error("expecting second dummy variable name", c_token);
  428.                 copy_str(dummy_var[1],c_token++);
  429.                 }
  430.         }
  431.     }
  432.     else if (almost_equals(c_token,"fo$rmat")) {
  433.         BOOLEAN setx, sety, setz;
  434.         c_token++;
  435.         if (equals(c_token,"x")) {
  436.             setx = TRUE; sety = setz = FALSE;
  437.             c_token++;
  438.         }
  439.         else if (equals(c_token,"y")) {
  440.             setx = setz = FALSE; sety = TRUE;
  441.             c_token++;
  442.         }
  443.         else if (equals(c_token,"z")) {
  444.             setx = sety = FALSE; setz = TRUE;
  445.             c_token++;
  446.         }
  447.         else if (equals(c_token,"xy") || equals(c_token,"yx")) {
  448.             setx = sety = TRUE; setz = FALSE;
  449.             c_token++;
  450.         }
  451.         else if (isstring(c_token) || END_OF_COMMAND) {
  452.             /* Assume he wants all */
  453.             setx = sety = setz = TRUE;
  454.         }
  455.         if (END_OF_COMMAND) {
  456.             if (setx)
  457.                 (void) strcpy(xformat,DEF_FORMAT);
  458.             if (sety)
  459.                 (void) strcpy(yformat,DEF_FORMAT);
  460.             if (setz)
  461.                 (void) strcpy(zformat,DEF_FORMAT);
  462.         }
  463.         else {
  464.             if (!isstring(c_token))
  465.               int_error("expecting format string",c_token);
  466.             else {
  467.                 if (setx)
  468.                  quote_str(xformat,c_token);
  469.                 if (sety)
  470.                  quote_str(yformat,c_token);
  471.                 if (setz)
  472.                  quote_str(zformat,c_token);
  473.                 c_token++;
  474.             }
  475.         }
  476.     }
  477.     else if (almost_equals(c_token,"fu$nction")) {
  478.         c_token++;
  479.         if (!almost_equals(c_token,"s$tyle"))
  480.             int_error("expecting keyword 'style'",c_token);
  481.         func_style = get_style();
  482.     }
  483.     else if (almost_equals(c_token,"la$bel")) {
  484.         c_token++;
  485.         set_label();
  486.     }
  487.     else if (almost_equals(c_token,"nola$bel")) {
  488.         c_token++;
  489.         set_nolabel();
  490.     }
  491.     else if (almost_equals(c_token,"lo$gscale")) {
  492.         c_token++;
  493.         if (END_OF_COMMAND) {
  494.            log_x = log_y = log_z = TRUE;
  495.         } else {
  496.            if (chr_in_str(c_token, 'x'))
  497.                log_x = TRUE;
  498.            if (chr_in_str(c_token, 'y'))
  499.                log_y = TRUE;
  500.            if (chr_in_str(c_token, 'z'))
  501.                log_z = TRUE;
  502.            c_token++;
  503.         }
  504.     }
  505.     else if (almost_equals(c_token,"nolo$gscale")) {
  506.         c_token++;
  507.         if (END_OF_COMMAND) {
  508.         log_x = log_y = log_z = FALSE;
  509.         } else {
  510.         if (chr_in_str(c_token, 'x'))
  511.             log_x = FALSE;
  512.         if (chr_in_str(c_token, 'y'))
  513.             log_y = FALSE;
  514.         if (chr_in_str(c_token, 'z'))
  515.             log_z = FALSE;
  516.         c_token++;
  517.         }
  518.     } 
  519.     else if (almost_equals(c_token,"of$fsets")) {
  520.         c_token++;
  521.         if (END_OF_COMMAND) {
  522.             loff = roff = toff = boff = 0.0;  /* Reset offsets */
  523.         }
  524.         else {
  525.             load_offsets (&loff,&roff,&toff,&boff);
  526.         }
  527.     }
  528.     else
  529.         return(FALSE);    /* no command match */
  530.     return(TRUE);
  531. }
  532.  
  533.  
  534. /* return TRUE if a command match, FALSE if not */
  535. static BOOLEAN
  536. set_two()
  537. {
  538.      char testfile[MAX_LINE_LEN+1];
  539. #ifdef unix
  540.      static BOOLEAN pipe_open = FALSE;
  541. #endif
  542.  
  543.     if (almost_equals(c_token,"o$utput")) {
  544.         register FILE *f;
  545.  
  546.         c_token++;
  547.         if (term && term_init)
  548.             (*term_tbl[term].reset)();
  549.         if (END_OF_COMMAND) {    /* no file specified */
  550.              UP_redirect (4);
  551.             if (outfile != stdout) { /* Never close stdout */
  552. #ifdef unix
  553.                 if ( pipe_open ) {
  554.                     (void) pclose(outfile);
  555.                     pipe_open = FALSE;
  556.                 } else
  557. #endif
  558.                     (void) fclose(outfile);
  559.             }
  560.             outfile = stdout; /* Don't dup... */
  561.             term_init = FALSE;
  562.             (void) strcpy(outstr,"STDOUT");
  563.         } else if (!isstring(c_token))
  564.             int_error("expecting filename",c_token);
  565.         else {
  566.             quote_str(testfile,c_token);
  567. #ifdef unix
  568.             if ( *testfile == '|' ) {
  569.               if ((f = popen(testfile+1,"w")) == (FILE *)NULL)
  570.                 os_error("cannot create pipe; output not changed",c_token);
  571.               else
  572.                 pipe_open = TRUE;
  573.             } else
  574. #endif
  575.               if ((f = fopen(testfile,"w")) == (FILE *)NULL)
  576.                 os_error("cannot open file; output not changed",c_token);
  577.             if (outfile != stdout) /* Never close stdout */
  578.                 (void) fclose(outfile);
  579.             outfile = f;
  580.             term_init = FALSE;
  581.             outstr[0] = '\'';
  582.             (void) strcat(strcpy(outstr+1,testfile),"'");
  583.              UP_redirect (1);
  584.         }
  585.         c_token++;
  586.     }
  587.     else if (almost_equals(c_token,"tit$le")) {
  588.         set_xyzlabel(title,&title_xoffset,&title_yoffset);
  589.     }
  590.     else if (almost_equals(c_token,"xl$abel")) {
  591.         set_xyzlabel(xlabel,&xlabel_xoffset,&xlabel_yoffset);
  592.     }
  593.     else if (almost_equals(c_token,"yl$abel")) {
  594.         set_xyzlabel(ylabel,&ylabel_xoffset,&ylabel_yoffset);
  595.     }
  596.     else if (almost_equals(c_token,"zl$abel")) {
  597.         set_xyzlabel(zlabel,&zlabel_xoffset,&zlabel_yoffset);
  598.     }
  599.     else if (almost_equals(c_token,"xzero$axis")) {
  600.         c_token++;
  601.         xzeroaxis = TRUE;
  602.     } 
  603.     else if (almost_equals(c_token,"yzero$axis")) {
  604.         c_token++;
  605.         yzeroaxis = TRUE;
  606.     } 
  607.     else if (almost_equals(c_token,"zeroa$xis")) {
  608.         c_token++;
  609.         yzeroaxis = TRUE;
  610.         xzeroaxis = TRUE;
  611.     } 
  612.     else if (almost_equals(c_token,"noxzero$axis")) {
  613.         c_token++;
  614.         xzeroaxis = FALSE;
  615.     } 
  616.     else if (almost_equals(c_token,"noyzero$axis")) {
  617.         c_token++;
  618.         yzeroaxis = FALSE;
  619.     } 
  620.     else if (almost_equals(c_token,"nozero$axis")) {
  621.         c_token++;
  622.         xzeroaxis = FALSE;
  623.         yzeroaxis = FALSE;
  624.     } 
  625.     else if (almost_equals(c_token,"par$ametric")) {
  626.         if (!parametric) {
  627.            parametric = TRUE;
  628.            strcpy (dummy_var[0], "t");
  629.            strcpy (dummy_var[1], "y");
  630.              (void) fprintf(stderr,"\n\tdummy variable is t for curves, u/v for surfaces\n");
  631.         }
  632.         c_token++;
  633.     }
  634.     else if (almost_equals(c_token,"nopar$ametric")) {
  635.         if (parametric) {
  636.            parametric = FALSE;
  637.            strcpy (dummy_var[0], "x");
  638.            strcpy (dummy_var[1], "y");
  639.              (void) fprintf(stderr,"\n\tdummy variable is x for curves, x/y for surfaces\n");
  640.         }
  641.         c_token++;
  642.     }
  643.     else if (almost_equals(c_token,"pol$ar")) {
  644.         if (!polar) {
  645.             polar = TRUE;
  646.             if (parametric) {
  647.                 tmin = 0.0;
  648.                 tmax = 2*Pi;
  649.             } else if (angles_format == ANGLES_DEGREES) {
  650.                 xmin = 0.0;
  651.                 xmax = 360.0;
  652.             } else {
  653.                 xmin = 0.0;
  654.                 xmax = 2*Pi;
  655.             }
  656.         }
  657.         c_token++;
  658.     }
  659.     else if (almost_equals(c_token,"nopo$lar")) {
  660.         if (polar) {
  661.             polar = FALSE;
  662.             if (parametric) {
  663.                 tmin = -5.0;
  664.                 tmax = 5.0;
  665.             } else {
  666.                 xmin = -10.0;
  667.                 xmax = 10.0;
  668.             }
  669.         }
  670.         c_token++;
  671.     }
  672.     else if (almost_equals(c_token,"an$gles")) {
  673.         c_token++;
  674.         if (END_OF_COMMAND) {
  675.         /* assuming same as defaults */
  676.         angles_format = ANGLES_RADIANS;
  677.         }
  678.         else if (almost_equals(c_token, "r$adians")) {
  679.         angles_format = ANGLES_RADIANS;
  680.         c_token++;
  681.         }
  682.         else if (almost_equals(c_token, "d$egrees")) {
  683.         angles_format = ANGLES_DEGREES;
  684.         c_token++;
  685.         }
  686.         else
  687.          int_error("expecting 'radians' or 'degrees'", c_token);
  688.     }
  689.     else if (almost_equals(c_token,"g$rid")) {
  690.         grid = TRUE;
  691.         c_token++;
  692.     }
  693.     else if (almost_equals(c_token,"nog$rid")) {
  694.         grid = FALSE;
  695.         c_token++;
  696.     }
  697.     else if (almost_equals(c_token,"su$rface")) {
  698.         draw_surface = TRUE;
  699.         c_token++;
  700.     }
  701.     else if (almost_equals(c_token,"nosu$rface")) {
  702.         draw_surface = FALSE;
  703.         c_token++;
  704.     }
  705.     else if (almost_equals(c_token,"k$ey")) {
  706.         struct value a;
  707.         c_token++;
  708.         if (END_OF_COMMAND) {
  709.             key = -1;
  710.         } 
  711.         else {
  712.             key_x = real(const_express(&a));
  713.             if (!equals(c_token,","))
  714.                 int_error("',' expected",c_token);
  715.             c_token++;
  716.             key_y = real(const_express(&a));
  717.             if (equals(c_token,","))
  718.             {
  719.                     c_token++;
  720.                 key_z = real(const_express(&a));
  721.             }
  722.             key = 1;
  723.         } 
  724.     }
  725.     else if (almost_equals(c_token,"nok$ey")) {
  726.         key = 0;
  727.         c_token++;
  728.     }
  729.     else if (almost_equals(c_token,"tic$s")) {
  730.         tic_in = TRUE;
  731.         c_token++;
  732.         if (almost_equals(c_token,"i$n")) {
  733.             tic_in = TRUE;
  734.             c_token++;
  735.         }
  736.         else if (almost_equals(c_token,"o$ut")) {
  737.             tic_in = FALSE;
  738.             c_token++;
  739.         }
  740.     }
  741.      else if (almost_equals(c_token,"xt$ics")) {
  742.         xtics = TRUE;
  743.         c_token++;
  744.         if (END_OF_COMMAND) { /* reset to default */
  745.            if (xticdef.type == TIC_USER) {
  746.               free_marklist(xticdef.def.user);
  747.               xticdef.def.user = NULL;
  748.            }
  749.            xticdef.type = TIC_COMPUTED;
  750.         }
  751.         else
  752.          load_tics(&xticdef);
  753.     } 
  754.      else if (almost_equals(c_token,"noxt$ics")) {
  755.         xtics = FALSE;
  756.         c_token++;
  757.     } 
  758.      else if (almost_equals(c_token,"yt$ics")) {
  759.         ytics = TRUE;
  760.         c_token++;
  761.         if (END_OF_COMMAND) { /* reset to default */
  762.            if (yticdef.type == TIC_USER) {
  763.               free_marklist(yticdef.def.user);
  764.               yticdef.def.user = NULL;
  765.            }
  766.            yticdef.type = TIC_COMPUTED;
  767.         }
  768.         else
  769.          load_tics(&yticdef);
  770.     } 
  771.      else if (almost_equals(c_token,"noyt$ics")) {
  772.         ytics = FALSE;
  773.         c_token++;
  774.     } 
  775.      else if (almost_equals(c_token,"zt$ics")) {
  776.         ztics = TRUE;
  777.         c_token++;
  778.         if (END_OF_COMMAND) { /* reset to default */
  779.            if (zticdef.type == TIC_USER) {
  780.               free_marklist(zticdef.def.user);
  781.               zticdef.def.user = NULL;
  782.            }
  783.            zticdef.type = TIC_COMPUTED;
  784.         }
  785.         else
  786.          load_tics(&zticdef);
  787.     } 
  788.      else if (almost_equals(c_token,"nozt$ics")) {
  789.         ztics = FALSE;
  790.         c_token++;
  791.     } 
  792.     else if (almost_equals(c_token,"ticsl$evel")) {
  793.         double tlvl;
  794.         struct value a;
  795.  
  796.         c_token++;
  797.         tlvl = real(const_express(&a));
  798.         if (tlvl < 0.0)
  799.             int_error("tics level must be > 0; ticslevel unchanged",
  800.                 c_token);
  801.         else {
  802.             ticslevel = tlvl;
  803.         }
  804.     }
  805.     else
  806.     return(FALSE);    /* no command match */
  807.  
  808.     return(TRUE);
  809. }
  810.  
  811.  
  812.  
  813. /* return TRUE if a command match, FALSE if not */
  814. static BOOLEAN
  815. set_three()
  816. {
  817.      if (almost_equals(c_token,"sa$mples")) {
  818.         register int tsamp;
  819.         struct value a;
  820.  
  821.         c_token++;
  822.         tsamp = (int)magnitude(const_express(&a));
  823.         if (tsamp < 2)
  824.             int_error("sampling rate must be > 1; sampling unchanged",
  825.                 c_token);
  826.         else {
  827.                 extern struct surface_points *first_3dplot;
  828.             register struct surface_points *f_3dp = first_3dplot;
  829.  
  830.             first_3dplot = NULL;
  831.             sp_free(f_3dp);
  832.  
  833.             samples = tsamp;
  834.         }
  835.     }
  836.     else if (almost_equals(c_token,"isosa$mples")) {
  837.         register int tsamp;
  838.         struct value a;
  839.  
  840.         c_token++;
  841.         tsamp = (int)magnitude(const_express(&a));
  842.         if (tsamp < 2)
  843.             int_error("sampling rate must be > 1; sampling unchanged",
  844.                 c_token);
  845.         else {
  846.                 extern struct curve_points *first_plot;
  847.                 extern struct surface_points *first_3dplot;
  848.             register struct curve_points *f_p = first_plot;
  849.             register struct surface_points *f_3dp = first_3dplot;
  850.  
  851.             first_plot = NULL;
  852.             first_3dplot = NULL;
  853.             cp_free(f_p);
  854.             sp_free(f_3dp);
  855.  
  856.             iso_samples = tsamp;
  857.         }
  858.     }
  859.     else if (almost_equals(c_token,"si$ze")) {
  860.         struct value s;
  861.         c_token++;
  862.         if (END_OF_COMMAND) {
  863.             xsize = 1.0;
  864.             ysize = 1.0;
  865.         } 
  866.         else {
  867.                 xsize=real(const_express(&s));
  868.                 if (!equals(c_token,","))
  869.                     int_error("',' expected",c_token);
  870.                 c_token++;
  871.                 ysize=real(const_express(&s));
  872.         } 
  873.     } 
  874.     else if (almost_equals(c_token,"t$erminal")) {
  875.         c_token++;
  876.         if (END_OF_COMMAND) {
  877.             list_terms();
  878.             screen_ok = FALSE;
  879.         }
  880.         else {
  881.             if (term && term_init) {
  882.                 (*term_tbl[term].reset)();
  883.                 (void) fflush(outfile);
  884.             }
  885.             term = set_term(c_token);
  886.             c_token++;
  887.  
  888.             /* get optional mode parameters */
  889.             if (term)
  890.                 (*term_tbl[term].options)();
  891.             if (interactive && *term_options)
  892.                 fprintf(stderr,"Options are '%s'\n",term_options);
  893.         }
  894.     }
  895.     else if (almost_equals(c_token,"tim$e")) {
  896.         timedate = TRUE;
  897.         c_token++;
  898.         if (!END_OF_COMMAND) {
  899.             struct value a;
  900.             int x, y;
  901.  
  902.             /* We have x,y offsets specified */
  903.             if (!equals(c_token,","))
  904.                 time_xoffset = (int)real(const_express(&a));
  905.             if (!END_OF_COMMAND && equals(c_token,",")) {
  906.                 c_token++;
  907.                 time_yoffset = (int)real(const_express(&a));
  908.             }
  909.         }
  910.     }
  911.     else if (almost_equals(c_token,"not$ime")) {
  912.         timedate = FALSE;
  913.         c_token++;
  914.     }
  915.     else if (almost_equals(c_token,"rr$ange")) {
  916.          BOOLEAN changed;
  917.         c_token++;
  918.         if (!equals(c_token,"["))
  919.             int_error("expecting '['",c_token);
  920.         c_token++;
  921.         changed = load_range(&rmin,&rmax);
  922.         if (!equals(c_token,"]"))
  923.           int_error("expecting ']'",c_token);
  924.         c_token++;
  925.         if (changed)
  926.           autoscale_r = FALSE;
  927.     }
  928.     else if (almost_equals(c_token,"tr$ange")) {
  929.          BOOLEAN changed;
  930.         c_token++;
  931.         if (!equals(c_token,"["))
  932.             int_error("expecting '['",c_token);
  933.         c_token++;
  934.         changed = load_range(&tmin,&tmax);
  935.         if (!equals(c_token,"]"))
  936.           int_error("expecting ']'",c_token);
  937.         c_token++;
  938.         if (changed)
  939.           autoscale_t = FALSE;
  940.     }
  941.     else if (almost_equals(c_token,"ur$ange")) {
  942.          BOOLEAN changed;
  943.         c_token++;
  944.         if (!equals(c_token,"["))
  945.             int_error("expecting '['",c_token);
  946.         c_token++;
  947.         changed = load_range(&umin,&umax);
  948.         if (!equals(c_token,"]"))
  949.           int_error("expecting ']'",c_token);
  950.         c_token++;
  951.         if (changed)
  952.           autoscale_u = FALSE;
  953.     }
  954.     else if (almost_equals(c_token,"vi$ew")) {
  955.         int i;
  956.         BOOLEAN was_comma = TRUE;
  957.         double local_vals[4];
  958.         struct value a;
  959.  
  960.         local_vals[0] = surface_rot_x;
  961.         local_vals[1] = surface_rot_z;
  962.         local_vals[2] = surface_scale;
  963.         local_vals[3] = surface_zscale;
  964.         c_token++;
  965.         for (i = 0; i < 4 && !(END_OF_COMMAND);) {
  966.             if (equals(c_token,",")) {
  967.                 if (was_comma) i++;
  968.                 was_comma = TRUE;
  969.                 c_token++;
  970.             }
  971.             else {
  972.                 if (!was_comma)
  973.                     int_error("',' expected",c_token);
  974.                 local_vals[i] = real(const_express(&a));
  975.                 i++;
  976.                 was_comma = FALSE;
  977.             }
  978.         }
  979.  
  980.         if (local_vals[0] < 0 || local_vals[0] > 180)
  981.             int_error("rot_x must be in [0:180] degrees range; view unchanged",
  982.                   c_token);
  983.         if (local_vals[1] < 0 || local_vals[1] > 360)
  984.             int_error("rot_z must be in [0:360] degrees range; view unchanged",
  985.                   c_token);
  986.         if (local_vals[2] < 1e-6)
  987.             int_error("scale must be > 0; view unchanged", c_token);
  988.         if (local_vals[3] < 1e-6)
  989.             int_error("zscale must be > 0; view unchanged", c_token);
  990.  
  991.         surface_rot_x = local_vals[0];
  992.         surface_rot_z = local_vals[1];
  993.         surface_scale = local_vals[2];
  994.         surface_zscale = local_vals[3];
  995.     }
  996.     else if (almost_equals(c_token,"vr$ange")) {
  997.          BOOLEAN changed;
  998.         c_token++;
  999.         if (!equals(c_token,"["))
  1000.             int_error("expecting '['",c_token);
  1001.         c_token++;
  1002.         changed = load_range(&vmin,&vmax);
  1003.         if (!equals(c_token,"]"))
  1004.           int_error("expecting ']'",c_token);
  1005.         c_token++;
  1006.         if (changed)
  1007.           autoscale_v = FALSE;
  1008.     }
  1009.     else if (almost_equals(c_token,"xr$ange")) {
  1010.          BOOLEAN changed;
  1011.         c_token++;
  1012.         if (!equals(c_token,"["))
  1013.             int_error("expecting '['",c_token);
  1014.         c_token++;
  1015.         changed = load_range(&xmin,&xmax);
  1016.         if (!equals(c_token,"]"))
  1017.           int_error("expecting ']'",c_token);
  1018.         c_token++;
  1019.         if (changed)
  1020.           autoscale_x = FALSE;
  1021.     }
  1022.     else if (almost_equals(c_token,"yr$ange")) {
  1023.          BOOLEAN changed;
  1024.         c_token++;
  1025.         if (!equals(c_token,"["))
  1026.             int_error("expecting '['",c_token);
  1027.         c_token++;
  1028.         changed = load_range(&ymin,&ymax);
  1029.         if (!equals(c_token,"]"))
  1030.           int_error("expecting ']'",c_token);
  1031.         c_token++;
  1032.         if (changed)
  1033.           autoscale_y = FALSE;
  1034.     }
  1035.     else if (almost_equals(c_token,"zr$ange")) {
  1036.          BOOLEAN changed;
  1037.         c_token++;
  1038.         if (!equals(c_token,"["))
  1039.             int_error("expecting '['",c_token);
  1040.         c_token++;
  1041.         changed = load_range(&zmin,&zmax);
  1042.         if (!equals(c_token,"]"))
  1043.           int_error("expecting ']'",c_token);
  1044.         c_token++;
  1045.         if (changed)
  1046.           autoscale_z = FALSE;
  1047.     }
  1048.     else if (almost_equals(c_token,"z$ero")) {
  1049.         struct value a;
  1050.         c_token++;
  1051.         zero = magnitude(const_express(&a));
  1052.     }
  1053.     else
  1054.         return(FALSE);    /* no command match */
  1055.     return(TRUE);
  1056. }
  1057.  
  1058. /*********** Support functions for set_command ***********/
  1059.  
  1060. /* process a 'set {x/y/z}label command */
  1061. /* set {x/y/z}label {label_text} {x}{,y} */
  1062. static void set_xyzlabel(str,xpos,ypos)
  1063. char *str;
  1064. int *xpos,*ypos;
  1065. {
  1066.     c_token++;
  1067.     if (END_OF_COMMAND) {    /* no label specified */
  1068.         str[0] = '\0';
  1069.     } else {
  1070.         if (isstring(c_token)) {
  1071.             /* We have string specified - grab it. */
  1072.             quotel_str(str,c_token);
  1073.             c_token++;
  1074.         }
  1075.         if (!END_OF_COMMAND) {
  1076.             struct value a;
  1077.             int x, y;
  1078.  
  1079.             /* We have x,y offsets specified */
  1080.             if (!equals(c_token,","))
  1081.                 *xpos = (int)real(const_express(&a));
  1082.             if (!END_OF_COMMAND && equals(c_token,",")) {
  1083.                 c_token++;
  1084.                 *ypos = (int)real(const_express(&a));
  1085.             }
  1086.         }
  1087.     }
  1088. }
  1089.  
  1090. /* process a 'set label' command */
  1091. /* set label {tag} {label_text} {at x,y} {pos} */
  1092. static void
  1093. set_label()
  1094. {
  1095.     struct value a;
  1096.     struct text_label *this_label = NULL;
  1097.     struct text_label *new_label = NULL;
  1098.     struct text_label *prev_label = NULL;
  1099.     double x, y, z;
  1100.     char text[MAX_LINE_LEN+1];
  1101.     enum JUSTIFY just;
  1102.     int tag;
  1103.     BOOLEAN set_text, set_position, set_just;
  1104.  
  1105.     /* get tag */
  1106.     if (!END_OF_COMMAND 
  1107.        && !isstring(c_token) 
  1108.        && !equals(c_token, "at")
  1109.        && !equals(c_token, "left")
  1110.        && !equals(c_token, "center")
  1111.        && !equals(c_token, "centre")
  1112.        && !equals(c_token, "right")) {
  1113.        /* must be a tag expression! */
  1114.        tag = (int)real(const_express(&a));
  1115.        if (tag <= 0)
  1116.         int_error("tag must be > zero", c_token);
  1117.     } else
  1118.      tag = assign_label_tag(); /* default next tag */
  1119.      
  1120.     /* get text */
  1121.     if (!END_OF_COMMAND && isstring(c_token)) {
  1122.        /* get text */
  1123.        quotel_str(text, c_token);
  1124.        c_token++;
  1125.        set_text = TRUE;
  1126.     } else {
  1127.        text[0] = '\0';        /* default no text */
  1128.        set_text = FALSE;
  1129.     }
  1130.      
  1131.     /* get justification - what the heck, let him put it here */
  1132.     if (!END_OF_COMMAND && !equals(c_token, "at")) {
  1133.        if (almost_equals(c_token,"l$eft")) {
  1134.           just = LEFT;
  1135.        }
  1136.        else if (almost_equals(c_token,"c$entre")
  1137.               || almost_equals(c_token,"c$enter")) {
  1138.           just = CENTRE;
  1139.        }
  1140.        else if (almost_equals(c_token,"r$ight")) {
  1141.           just = RIGHT;
  1142.        }
  1143.        else
  1144.         int_error("bad syntax in set label", c_token);
  1145.        c_token++;
  1146.        set_just = TRUE;
  1147.     } else {
  1148.        just = LEFT;            /* default left justified */
  1149.        set_just = FALSE;
  1150.     } 
  1151.  
  1152.     /* get position */
  1153.     if (!END_OF_COMMAND && equals(c_token, "at")) {
  1154.        c_token++;
  1155.        if (END_OF_COMMAND)
  1156.         int_error("coordinates expected", c_token);
  1157.        /* get coordinates */
  1158.        x = real(const_express(&a));
  1159.        if (!equals(c_token,","))
  1160.         int_error("',' expected",c_token);
  1161.        c_token++;
  1162.        y = real(const_express(&a));
  1163.        if (equals(c_token,",")) {
  1164.         c_token++;
  1165.         z = real(const_express(&a));
  1166.        }
  1167.        else
  1168.             z = 0;
  1169.        set_position = TRUE;
  1170.     } else {
  1171.        x = y = z = 0;            /* default at origin */
  1172.        set_position = FALSE;
  1173.     }
  1174.  
  1175.     /* get justification */
  1176.     if (!END_OF_COMMAND) {
  1177.        if (set_just)
  1178.         int_error("only one justification is allowed", c_token);
  1179.        if (almost_equals(c_token,"l$eft")) {
  1180.           just = LEFT;
  1181.        }
  1182.        else if (almost_equals(c_token,"c$entre")
  1183.               || almost_equals(c_token,"c$enter")) {
  1184.           just = CENTRE;
  1185.        }
  1186.        else if (almost_equals(c_token,"r$ight")) {
  1187.           just = RIGHT;
  1188.        }
  1189.        else
  1190.         int_error("bad syntax in set label", c_token);
  1191.        c_token++;
  1192.        set_just = TRUE;
  1193.     } 
  1194.  
  1195.     if (!END_OF_COMMAND)
  1196.      int_error("extraenous or out-of-order arguments in set label", c_token);
  1197.  
  1198.     /* OK! add label */
  1199.     if (first_label != NULL) { /* skip to last label */
  1200.        for (this_label = first_label; this_label != NULL ; 
  1201.            prev_label = this_label, this_label = this_label->next)
  1202.         /* is this the label we want? */
  1203.         if (tag <= this_label->tag)
  1204.           break;
  1205.     }
  1206.     if (this_label != NULL && tag == this_label->tag) {
  1207.        /* changing the label */
  1208.        if (set_position) {
  1209.           this_label->x = x;
  1210.           this_label->y = y;
  1211.           this_label->z = z;
  1212.        }
  1213.        if (set_text)
  1214.         (void) strcpy(this_label->text, text);
  1215.        if (set_just)
  1216.         this_label->pos = just;
  1217.     } else {
  1218.        /* adding the label */
  1219.        new_label = (struct text_label *) 
  1220.         alloc ( (unsigned int) sizeof(struct text_label), "label");
  1221.        if (prev_label != NULL)
  1222.         prev_label->next = new_label; /* add it to end of list */
  1223.        else 
  1224.         first_label = new_label; /* make it start of list */
  1225.        new_label->tag = tag;
  1226.        new_label->next = this_label;
  1227.        new_label->x = x;
  1228.        new_label->y = y;
  1229.        new_label->z = z;
  1230.        (void) strcpy(new_label->text, text);
  1231.        new_label->pos = just;
  1232.     }
  1233. }
  1234.  
  1235. /* process 'set nolabel' command */
  1236. /* set nolabel {tag} */
  1237. static void
  1238. set_nolabel()
  1239. {
  1240.     struct value a;
  1241.     struct text_label *this_label;
  1242.     struct text_label *prev_label; 
  1243.     int tag;
  1244.  
  1245.     if (END_OF_COMMAND) {
  1246.        /* delete all labels */
  1247.        while (first_label != NULL)
  1248.         delete_label((struct text_label *)NULL,first_label);
  1249.     }
  1250.     else {
  1251.        /* get tag */
  1252.        tag = (int)real(const_express(&a));
  1253.        if (!END_OF_COMMAND)
  1254.         int_error("extraneous arguments to set nolabel", c_token);
  1255.        for (this_label = first_label, prev_label = NULL;
  1256.            this_label != NULL;
  1257.            prev_label = this_label, this_label = this_label->next) {
  1258.           if (this_label->tag == tag) {
  1259.              delete_label(prev_label,this_label);
  1260.              return;        /* exit, our job is done */
  1261.           }
  1262.        }
  1263.        int_error("label not found", c_token);
  1264.     }
  1265. }
  1266.  
  1267. /* assign a new label tag */
  1268. /* labels are kept sorted by tag number, so this is easy */
  1269. static int                /* the lowest unassigned tag number */
  1270. assign_label_tag()
  1271. {
  1272.     struct text_label *this_label;
  1273.     int last = 0;            /* previous tag value */
  1274.  
  1275.     for (this_label = first_label; this_label != NULL;
  1276.         this_label = this_label->next)
  1277.      if (this_label->tag == last+1)
  1278.        last++;
  1279.      else
  1280.        break;
  1281.     
  1282.     return (last+1);
  1283. }
  1284.  
  1285. /* delete label from linked list started by first_label.
  1286.  * called with pointers to the previous label (prev) and the 
  1287.  * label to delete (this).
  1288.  * If there is no previous label (the label to delete is
  1289.  * first_label) then call with prev = NULL.
  1290.  */
  1291. static void
  1292. delete_label(prev,this)
  1293.     struct text_label *prev, *this;
  1294. {
  1295.     if (this!=NULL)    {        /* there really is something to delete */
  1296.        if (prev!=NULL)        /* there is a previous label */
  1297.         prev->next = this->next; 
  1298.        else                /* this = first_label so change first_label */
  1299.         first_label = this->next;
  1300.        free((char *)this);
  1301.     }
  1302. }
  1303.  
  1304.  
  1305. /* process a 'set arrow' command */
  1306. /* set arrow {tag} {from x,y} {to x,y} {{no}head} */
  1307. static void
  1308. set_arrow()
  1309. {
  1310.     struct value a;
  1311.     struct arrow_def *this_arrow = NULL;
  1312.     struct arrow_def *new_arrow = NULL;
  1313.     struct arrow_def *prev_arrow = NULL;
  1314.     double sx, sy, sz;
  1315.     double ex, ey, ez;
  1316.     int tag;
  1317.     BOOLEAN set_start, set_end, head = 1;
  1318.  
  1319.     /* get tag */
  1320.     if (!END_OF_COMMAND 
  1321.        && !equals(c_token, "from")
  1322.        && !equals(c_token, "to")) {
  1323.        /* must be a tag expression! */
  1324.        tag = (int)real(const_express(&a));
  1325.        if (tag <= 0)
  1326.         int_error("tag must be > zero", c_token);
  1327.     } else
  1328.      tag = assign_arrow_tag(); /* default next tag */
  1329.      
  1330.     /* get start position */
  1331.     if (!END_OF_COMMAND && equals(c_token, "from")) {
  1332.        c_token++;
  1333.        if (END_OF_COMMAND)
  1334.         int_error("start coordinates expected", c_token);
  1335.        /* get coordinates */
  1336.        sx = real(const_express(&a));
  1337.        if (!equals(c_token,","))
  1338.         int_error("',' expected",c_token);
  1339.        c_token++;
  1340.        sy = real(const_express(&a));
  1341.        if (equals(c_token,",")) {
  1342.         c_token++;
  1343.         sz = real(const_express(&a));
  1344.        }
  1345.        else
  1346.            sz = 0;
  1347.        set_start = TRUE;
  1348.     } else {
  1349.        sx = sy = sz = 0;            /* default at origin */
  1350.        set_start = FALSE;
  1351.     }
  1352.  
  1353.     /* get end position */
  1354.     if (!END_OF_COMMAND && equals(c_token, "to")) {
  1355.        c_token++;
  1356.        if (END_OF_COMMAND)
  1357.         int_error("end coordinates expected", c_token);
  1358.        /* get coordinates */
  1359.        ex = real(const_express(&a));
  1360.        if (!equals(c_token,","))
  1361.         int_error("',' expected",c_token);
  1362.        c_token++;
  1363.        ey = real(const_express(&a));
  1364.        if (equals(c_token,",")) {
  1365.         c_token++;
  1366.         ez = real(const_express(&a));
  1367.        }
  1368.        else
  1369.         ez = 0;
  1370.        set_end = TRUE;
  1371.     } else {
  1372.        ex = ey = ez = 0;            /* default at origin */
  1373.        set_end = FALSE;
  1374.     }
  1375.  
  1376.     /* get start position - what the heck, either order is ok */
  1377.     if (!END_OF_COMMAND && equals(c_token, "from")) {
  1378.        if (set_start)
  1379.         int_error("only one 'from' is allowed", c_token);
  1380.        c_token++;
  1381.        if (END_OF_COMMAND)
  1382.         int_error("start coordinates expected", c_token);
  1383.        /* get coordinates */
  1384.        sx = real(const_express(&a));
  1385.        if (!equals(c_token,","))
  1386.         int_error("',' expected",c_token);
  1387.        c_token++;
  1388.        sy = real(const_express(&a));
  1389.        if (equals(c_token,",")) {
  1390.         c_token++;
  1391.         sz = real(const_express(&a));
  1392.        }
  1393.        else
  1394.            sz = 0;
  1395.        set_start = TRUE;
  1396.     }
  1397.  
  1398.     if (!END_OF_COMMAND && equals(c_token, "nohead")) {
  1399.        c_token++;
  1400.            head = 0;
  1401.     }
  1402.  
  1403.     if (!END_OF_COMMAND && equals(c_token, "head")) {
  1404.        c_token++;
  1405.            head = 1;
  1406.     }
  1407.  
  1408.     if (!END_OF_COMMAND)
  1409.      int_error("extraneous or out-of-order arguments in set arrow", c_token);
  1410.  
  1411.     /* OK! add arrow */
  1412.     if (first_arrow != NULL) { /* skip to last arrow */
  1413.        for (this_arrow = first_arrow; this_arrow != NULL ; 
  1414.            prev_arrow = this_arrow, this_arrow = this_arrow->next)
  1415.         /* is this the arrow we want? */
  1416.         if (tag <= this_arrow->tag)
  1417.           break;
  1418.     }
  1419.     if (this_arrow != NULL && tag == this_arrow->tag) {
  1420.        /* changing the arrow */
  1421.        if (set_start) {
  1422.           this_arrow->sx = sx;
  1423.           this_arrow->sy = sy;
  1424.           this_arrow->sz = sz;
  1425.        }
  1426.        if (set_end) {
  1427.           this_arrow->ex = ex;
  1428.           this_arrow->ey = ey;
  1429.           this_arrow->ez = ez;
  1430.        }
  1431.        this_arrow->head = head;
  1432.     } else {
  1433.        /* adding the arrow */
  1434.        new_arrow = (struct arrow_def *) 
  1435.         alloc ( (unsigned int) sizeof(struct arrow_def), "arrow");
  1436.        if (prev_arrow != NULL)
  1437.         prev_arrow->next = new_arrow; /* add it to end of list */
  1438.        else 
  1439.         first_arrow = new_arrow; /* make it start of list */
  1440.        new_arrow->tag = tag;
  1441.        new_arrow->next = this_arrow;
  1442.        new_arrow->sx = sx;
  1443.        new_arrow->sy = sy;
  1444.        new_arrow->sz = sz;
  1445.        new_arrow->ex = ex;
  1446.        new_arrow->ey = ey;
  1447.        new_arrow->ez = ez;
  1448.        new_arrow->head = head;
  1449.     }
  1450. }
  1451.  
  1452. /* process 'set noarrow' command */
  1453. /* set noarrow {tag} */
  1454. static void
  1455. set_noarrow()
  1456. {
  1457.     struct value a;
  1458.     struct arrow_def *this_arrow;
  1459.     struct arrow_def *prev_arrow; 
  1460.     int tag;
  1461.  
  1462.     if (END_OF_COMMAND) {
  1463.        /* delete all arrows */
  1464.        while (first_arrow != NULL)
  1465.         delete_arrow((struct arrow_def *)NULL,first_arrow);
  1466.     }
  1467.     else {
  1468.        /* get tag */
  1469.        tag = (int)real(const_express(&a));
  1470.        if (!END_OF_COMMAND)
  1471.         int_error("extraneous arguments to set noarrow", c_token);
  1472.        for (this_arrow = first_arrow, prev_arrow = NULL;
  1473.            this_arrow != NULL;
  1474.            prev_arrow = this_arrow, this_arrow = this_arrow->next) {
  1475.           if (this_arrow->tag == tag) {
  1476.              delete_arrow(prev_arrow,this_arrow);
  1477.              return;        /* exit, our job is done */
  1478.           }
  1479.        }
  1480.        int_error("arrow not found", c_token);
  1481.     }
  1482. }
  1483.  
  1484. /* assign a new arrow tag */
  1485. /* arrows are kept sorted by tag number, so this is easy */
  1486. static int                /* the lowest unassigned tag number */
  1487. assign_arrow_tag()
  1488. {
  1489.     struct arrow_def *this_arrow;
  1490.     int last = 0;            /* previous tag value */
  1491.  
  1492.     for (this_arrow = first_arrow; this_arrow != NULL;
  1493.         this_arrow = this_arrow->next)
  1494.      if (this_arrow->tag == last+1)
  1495.        last++;
  1496.      else
  1497.        break;
  1498.  
  1499.     return (last+1);
  1500. }
  1501.  
  1502. /* delete arrow from linked list started by first_arrow.
  1503.  * called with pointers to the previous arrow (prev) and the 
  1504.  * arrow to delete (this).
  1505.  * If there is no previous arrow (the arrow to delete is
  1506.  * first_arrow) then call with prev = NULL.
  1507.  */
  1508. static void
  1509. delete_arrow(prev,this)
  1510.     struct arrow_def *prev, *this;
  1511. {
  1512.     if (this!=NULL)    {        /* there really is something to delete */
  1513.        if (prev!=NULL)        /* there is a previous arrow */
  1514.         prev->next = this->next; 
  1515.        else                /* this = first_arrow so change first_arrow */
  1516.         first_arrow = this->next;
  1517.        free((char *)this);
  1518.     }
  1519. }
  1520.  
  1521.  
  1522. enum PLOT_STYLE            /* not static; used by command.c */
  1523. get_style()
  1524. {
  1525. register enum PLOT_STYLE ps;
  1526.  
  1527.     c_token++;
  1528.     if (almost_equals(c_token,"l$ines"))
  1529.         ps = LINES;
  1530.     else if (almost_equals(c_token,"i$mpulses"))
  1531.         ps = IMPULSES;
  1532.     else if (almost_equals(c_token,"p$oints"))
  1533.         ps = POINTS;
  1534.     else if (almost_equals(c_token,"linesp$oints"))
  1535.         ps = LINESPOINTS;
  1536.     else if (almost_equals(c_token,"d$ots"))
  1537.         ps = DOTS;
  1538.     else if (almost_equals(c_token,"e$rrorbars"))
  1539.         ps = ERRORBARS;
  1540.     else
  1541.         int_error("expecting 'lines', 'points', 'linespoints', 'dots', 'impulses', or 'errorbars'",c_token);
  1542.     c_token++;
  1543.     return(ps);
  1544. }
  1545.  
  1546. /* For set [xy]tics... command*/
  1547. static void
  1548. load_tics(tdef)
  1549.     struct ticdef *tdef;    /* change this ticdef */
  1550. {
  1551.     if (equals(c_token,"(")) { /* set : TIC_USER */
  1552.        c_token++;
  1553.        load_tic_user(tdef);
  1554.     } else {                /* series : TIC_SERIES */
  1555.        load_tic_series(tdef);
  1556.     }
  1557. }
  1558.  
  1559. /* load TIC_USER definition */
  1560. /* (tic[,tic]...)
  1561.  * where tic is ["string"] value
  1562.  * Left paren is already scanned off before entry.
  1563.  */
  1564. static void
  1565. load_tic_user(tdef)
  1566.     struct ticdef *tdef;
  1567. {
  1568.     struct ticmark *list = NULL; /* start of list */
  1569.     struct ticmark *last = NULL; /* end of list */
  1570.     struct ticmark *tic = NULL; /* new ticmark */
  1571.     char temp_string[MAX_LINE_LEN];
  1572.     struct value a;
  1573.  
  1574.     while (!END_OF_COMMAND) {
  1575.        /* parse a new ticmark */
  1576.        tic = (struct ticmark *)alloc(sizeof(struct ticmark), (char *)NULL);
  1577.        if (tic == (struct ticmark *)NULL) {
  1578.           free_marklist(list);
  1579.           int_error("out of memory for tic mark", c_token);
  1580.        }
  1581.  
  1582.        /* has a string with it? */
  1583.        if (isstring(c_token)) {
  1584.           quote_str(temp_string,c_token);
  1585.           tic->label = alloc((unsigned int)strlen(temp_string)+1, "tic label");
  1586.           (void) strcpy(tic->label, temp_string);
  1587.           c_token++;
  1588.        } else
  1589.         tic->label = NULL;
  1590.  
  1591.        /* in any case get the value */
  1592.        tic->position = real(const_express(&a));
  1593.        tic->next = NULL;
  1594.  
  1595.        /* append to list */
  1596.        if (list == NULL)
  1597.         last = list = tic;    /* new list */
  1598.        else {                /* append to list */
  1599.           last->next = tic;
  1600.           last = tic;
  1601.        }
  1602.  
  1603.        /* expect "," or ")" here */
  1604.        if (!END_OF_COMMAND && equals(c_token, ","))
  1605.         c_token++;        /* loop again */
  1606.        else
  1607.         break;            /* hopefully ")" */
  1608.     }
  1609.     
  1610.     if (END_OF_COMMAND || !equals(c_token, ")")) {
  1611.        free_marklist(list);
  1612.        int_error("expecting right parenthesis )", c_token);
  1613.     }
  1614.     c_token++;
  1615.     
  1616.     /* successful list */
  1617.     if (tdef->type == TIC_USER) {
  1618.        /* remove old list */
  1619.         /* VAX Optimiser was stuffing up following line. Turn Optimiser OFF */
  1620.        free_marklist(tdef->def.user);
  1621.        tdef->def.user = NULL;
  1622.     }
  1623.     tdef->type = TIC_USER;
  1624.     tdef->def.user = list;
  1625. }
  1626.  
  1627. static void
  1628. free_marklist(list)
  1629.     struct ticmark *list;
  1630. {
  1631.     register struct ticmark *freeable;
  1632.  
  1633.     while (list != NULL) {
  1634.        freeable = list;
  1635.        list = list->next;
  1636.        if (freeable->label != NULL)
  1637.         free( (char *)freeable->label );
  1638.        free( (char *)freeable );
  1639.     }
  1640. }
  1641.  
  1642. /* load TIC_SERIES definition */
  1643. /* start,incr[,end] */
  1644. static void
  1645. load_tic_series(tdef)
  1646.     struct ticdef *tdef;
  1647. {
  1648.     double start, incr, end;
  1649.     struct value a;
  1650.     int incr_token;
  1651.  
  1652.     start = real(const_express(&a));
  1653.     if (!equals(c_token, ","))
  1654.      int_error("expecting comma to separate start,incr", c_token);
  1655.     c_token++;
  1656.  
  1657.     incr_token = c_token;
  1658.     incr = real(const_express(&a));
  1659.  
  1660.     if (END_OF_COMMAND)
  1661.      end = VERYLARGE;
  1662.     else {
  1663.        if (!equals(c_token, ","))
  1664.         int_error("expecting comma to separate incr,end", c_token);
  1665.        c_token++;
  1666.  
  1667.        end = real(const_express(&a));
  1668.     }
  1669.     if (!END_OF_COMMAND)
  1670.      int_error("tic series is defined by start,increment[,end]", 
  1671.              c_token);
  1672.     
  1673.     if (start < end && incr <= 0)
  1674.      int_error("increment must be positive", incr_token);
  1675.     if (start > end && incr >= 0)
  1676.      int_error("increment must be negative", incr_token);
  1677.     if (start > end) {
  1678.        /* put in order */
  1679.         double numtics;
  1680.         numtics = floor( (end*(1+SIGNIF) - start)/incr );
  1681.         end = start;
  1682.         start = end + numtics*incr;
  1683.         incr = -incr;
  1684. /*
  1685.        double temp = start;
  1686.        start = end;
  1687.        end = temp;
  1688.        incr = -incr;
  1689.  */
  1690.     }
  1691.  
  1692.     if (tdef->type == TIC_USER) {
  1693.        /* remove old list */
  1694.         /* VAX Optimiser was stuffing up following line. Turn Optimiser OFF */
  1695.        free_marklist(tdef->def.user);
  1696.        tdef->def.user = NULL;
  1697.     }
  1698.     tdef->type = TIC_SERIES;
  1699.     tdef->def.series.start = start;
  1700.     tdef->def.series.incr = incr;
  1701.     tdef->def.series.end = end;
  1702. }
  1703.  
  1704. static void
  1705. load_offsets (a, b, c, d)
  1706. double *a,*b, *c, *d;
  1707. {
  1708. struct value t;
  1709.  
  1710.     *a = real (const_express(&t));  /* loff value */
  1711.     c_token++;
  1712.     if (equals(c_token,","))
  1713.         c_token++;
  1714.     if (END_OF_COMMAND) 
  1715.         return;
  1716.  
  1717.     *b = real (const_express(&t));  /* roff value */
  1718.     c_token++;
  1719.     if (equals(c_token,","))
  1720.         c_token++;
  1721.     if (END_OF_COMMAND) 
  1722.         return;
  1723.  
  1724.     *c = real (const_express(&t));  /* toff value */
  1725.     c_token++;
  1726.     if (equals(c_token,","))
  1727.         c_token++;
  1728.     if (END_OF_COMMAND) 
  1729.         return;
  1730.  
  1731.     *d = real (const_express(&t));  /* boff value */
  1732.     c_token++;
  1733. }
  1734.  
  1735.  
  1736. BOOLEAN                    /* TRUE if a or b were changed */
  1737. load_range(a,b)            /* also used by command.c */
  1738. double *a,*b;
  1739. {
  1740. struct value t;
  1741. BOOLEAN changed = FALSE;
  1742.  
  1743.     if (equals(c_token,"]"))
  1744.         return(FALSE);
  1745.     if (END_OF_COMMAND) {
  1746.         int_error("starting range value or ':' or 'to' expected",c_token);
  1747.     } else if (!equals(c_token,"to") && !equals(c_token,":"))  {
  1748.         *a = real(const_express(&t));
  1749.         changed = TRUE;
  1750.     }    
  1751.     if (!equals(c_token,"to") && !equals(c_token,":"))
  1752.         int_error("':' or keyword 'to' expected",c_token);
  1753.     c_token++;
  1754.     if (!equals(c_token,"]")) {
  1755.         *b = real(const_express(&t));
  1756.         changed = TRUE;
  1757.      }
  1758.      return(changed);
  1759. }
  1760.  
  1761.  
  1762.  
  1763. /******* The 'show' command *******/
  1764. void
  1765. show_command()
  1766. {
  1767.     c_token++;
  1768.  
  1769.     if (!show_one() && !show_two())
  1770.     int_error(
  1771.     "valid show options:  'action_table', 'all', 'angles', 'arrow', \n\
  1772.     'autoscale', 'border', 'clip', 'contour', 'data', 'dummy', 'format', \n\
  1773.     'function', 'grid', 'hidden', 'key', 'label', 'logscale', 'mapping', \n\
  1774.     'offsets', 'output', 'plot', 'parametric', 'polar', 'rrange', \n\
  1775.     'samples', 'isosamples', 'view', 'size', 'terminal', 'tics', \n\
  1776.     'ticslevel', 'time', 'title', 'trange', 'urange', 'vrange', \n\
  1777.     'variables', 'version', 'xlabel', 'xrange', 'xtics', 'xzeroaxis', \n\
  1778.     'ylabel', 'yrange', 'ytics', 'yzeroaxis', 'zlabel', 'zrange', \n\
  1779.     'ztics', 'zero', 'zeroaxis'", c_token);
  1780.     screen_ok = FALSE;
  1781.     (void) putc('\n',stderr);
  1782. }
  1783.  
  1784. /* return TRUE if a command match, FALSE if not */
  1785. static BOOLEAN
  1786. show_one()
  1787. {
  1788.     if (almost_equals(c_token,"ac$tion_table") ||
  1789.              equals(c_token,"at") ) {
  1790.         c_token++; 
  1791.         show_at();
  1792.         c_token++;
  1793.     }
  1794.     else if (almost_equals(c_token,"ar$row")) {
  1795.         struct value a;
  1796.         int tag = 0;
  1797.  
  1798.         c_token++;
  1799.         if (!END_OF_COMMAND) {
  1800.            tag = (int)real(const_express(&a));
  1801.            if (tag <= 0)
  1802.             int_error("tag must be > zero", c_token);
  1803.         }
  1804.  
  1805.         (void) putc('\n',stderr);
  1806.         show_arrow(tag);
  1807.     }
  1808.     else if (almost_equals(c_token,"au$toscale")) {
  1809.         (void) putc('\n',stderr);
  1810.         show_autoscale();
  1811.         c_token++;
  1812.     }
  1813.     else if (almost_equals(c_token,"bor$der")) {
  1814.         (void) putc('\n',stderr);
  1815.         show_border();
  1816.         c_token++;
  1817.     }
  1818.     else if (almost_equals(c_token,"c$lip")) {
  1819.         (void) putc('\n',stderr);
  1820.         show_clip();
  1821.         c_token++;
  1822.     }
  1823.     else if (almost_equals(c_token,"ma$pping")) {
  1824.         (void) putc('\n',stderr);
  1825.         show_mapping();
  1826.         c_token++;
  1827.     }
  1828.     else if (almost_equals(c_token,"co$ntour")) {
  1829.         (void) putc('\n',stderr);
  1830.         show_contour();
  1831.         c_token++;
  1832.     }
  1833.     else if (almost_equals(c_token,"d$ata")) {
  1834.         c_token++;
  1835.         if (!almost_equals(c_token,"s$tyle"))
  1836.             int_error("expecting keyword 'style'",c_token);
  1837.         (void) putc('\n',stderr);
  1838.         show_style("data",data_style);
  1839.         c_token++;
  1840.     }
  1841.     else if (almost_equals(c_token,"d$ummy")) {
  1842.           (void) fprintf(stderr,"\n\tdummy variables are \"%s\" and \"%s\"\n",
  1843.                         dummy_var[0], dummy_var[1]);
  1844.         c_token++;
  1845.     }
  1846.     else if (almost_equals(c_token,"fo$rmat")) {
  1847.         show_format();
  1848.         c_token++;
  1849.     }
  1850.     else if (almost_equals(c_token,"f$unctions")) {
  1851.         c_token++;
  1852.         if (almost_equals(c_token,"s$tyle"))  {
  1853.             (void) putc('\n',stderr);
  1854.             show_style("functions",func_style);
  1855.             c_token++;
  1856.         }
  1857.         else
  1858.             show_functions();
  1859.     }
  1860.     else if (almost_equals(c_token,"lo$gscale")) {
  1861.         (void) putc('\n',stderr);
  1862.         show_logscale();
  1863.         c_token++;
  1864.     }
  1865.     else if (almost_equals(c_token,"of$fsets")) {
  1866.         (void) putc('\n',stderr);
  1867.         show_offsets();
  1868.         c_token++;
  1869.     }
  1870.     else if (almost_equals(c_token,"o$utput")) {
  1871.         (void) putc('\n',stderr);
  1872.         show_output();
  1873.         c_token++;
  1874.     }
  1875.     else if (almost_equals(c_token,"tit$le")) {
  1876.         (void) putc('\n',stderr);
  1877.         show_title();
  1878.         c_token++;
  1879.     }
  1880.     else if (almost_equals(c_token,"xl$abel")) {
  1881.         (void) putc('\n',stderr);
  1882.         show_xlabel();
  1883.         c_token++;
  1884.     }
  1885.     else if (almost_equals(c_token,"yl$abel")) {
  1886.         (void) putc('\n',stderr);
  1887.         show_ylabel();
  1888.         c_token++;
  1889.     }
  1890.     else if (almost_equals(c_token,"zl$abel")) {
  1891.         (void) putc('\n',stderr);
  1892.         show_zlabel();
  1893.         c_token++;
  1894.     }
  1895.     else if (almost_equals(c_token,"xzero$axis")) {
  1896.         (void) putc('\n',stderr);
  1897.         show_xzeroaxis();
  1898.         c_token++;
  1899.     }
  1900.     else if (almost_equals(c_token,"yzero$axis")) {
  1901.         (void) putc('\n',stderr);
  1902.         show_yzeroaxis();
  1903.         c_token++;
  1904.     }
  1905.     else if (almost_equals(c_token,"zeroa$xis")) {
  1906.         (void) putc('\n',stderr);
  1907.         show_xzeroaxis();
  1908.         show_yzeroaxis();
  1909.         c_token++;
  1910.     }
  1911.     else if (almost_equals(c_token,"la$bel")) {
  1912.         struct value a;
  1913.         int tag = 0;
  1914.  
  1915.         c_token++;
  1916.         if (!END_OF_COMMAND) {
  1917.            tag = (int)real(const_express(&a));
  1918.            if (tag <= 0)
  1919.             int_error("tag must be > zero", c_token);
  1920.         }
  1921.  
  1922.         (void) putc('\n',stderr);
  1923.         show_label(tag);
  1924.     }
  1925.     else if (almost_equals(c_token,"g$rid")) {
  1926.         (void) putc('\n',stderr);
  1927.         show_grid();
  1928.         c_token++;
  1929.     }
  1930.     else if (almost_equals(c_token,"k$ey")) {
  1931.         (void) putc('\n',stderr);
  1932.         show_key();
  1933.         c_token++;
  1934.     }
  1935.     else
  1936.         return (FALSE);
  1937.     return TRUE;
  1938. }
  1939.  
  1940. /* return TRUE if a command match, FALSE if not */
  1941. static BOOLEAN
  1942. show_two()
  1943. {
  1944.     if (almost_equals(c_token,"p$lot")) {
  1945.         (void) putc('\n',stderr);
  1946.         show_plot();
  1947.         c_token++;
  1948.     }
  1949.     else if (almost_equals(c_token,"par$ametric")) {
  1950.         (void) putc('\n',stderr);
  1951.         show_parametric();
  1952.         c_token++;
  1953.     }
  1954.     else if (almost_equals(c_token,"pol$ar")) {
  1955.         (void) putc('\n',stderr);
  1956.         show_polar();
  1957.         c_token++;
  1958.     }
  1959.     else if (almost_equals(c_token,"an$gles")) {
  1960.         (void) putc('\n',stderr);
  1961.         show_angles();
  1962.         c_token++;
  1963.     }
  1964.     else if (almost_equals(c_token,"ti$cs")) {
  1965.         (void) putc('\n',stderr);
  1966.         show_tics(TRUE,TRUE,TRUE);
  1967.         c_token++;
  1968.     }
  1969.     else if (almost_equals(c_token,"tim$e")) {
  1970.         (void) putc('\n',stderr);
  1971.         show_time();
  1972.         c_token++;
  1973.     }
  1974.     else if (almost_equals(c_token,"su$rface")) {
  1975.         (void) putc('\n',stderr);
  1976.         show_surface();
  1977.         c_token++;
  1978.     }
  1979.     else if (almost_equals(c_token,"hi$dden3d")) {
  1980.         (void) putc('\n',stderr);
  1981.         show_hidden3d();
  1982.         c_token++;
  1983.     }
  1984.     else if (almost_equals(c_token,"xti$cs")) {
  1985.         show_tics(TRUE,FALSE,FALSE);
  1986.         c_token++;
  1987.     }
  1988.     else if (almost_equals(c_token,"yti$cs")) {
  1989.         show_tics(FALSE,TRUE,FALSE);
  1990.         c_token++;
  1991.     }
  1992.     else if (almost_equals(c_token,"zti$cs")) {
  1993.         show_tics(FALSE,FALSE,TRUE);
  1994.         c_token++;
  1995.     }
  1996.     else if (almost_equals(c_token,"sa$mples")) {
  1997.         (void) putc('\n',stderr);
  1998.         show_samples();
  1999.         c_token++;
  2000.     }
  2001.     else if (almost_equals(c_token,"isosa$mples")) {
  2002.         (void) putc('\n',stderr);
  2003.         show_isosamples();
  2004.         c_token++;
  2005.     }
  2006.     else if (almost_equals(c_token,"si$ze")) {
  2007.         (void) putc('\n',stderr);
  2008.         show_size();
  2009.         c_token++;
  2010.     }
  2011.     else if (almost_equals(c_token,"t$erminal")) {
  2012.         (void) putc('\n',stderr);
  2013.         show_term();
  2014.         c_token++;
  2015.     }
  2016.     else if (almost_equals(c_token,"rr$ange")) {
  2017.         (void) putc('\n',stderr);
  2018.         show_range('r',rmin,rmax);
  2019.         c_token++;
  2020.     }
  2021.     else if (almost_equals(c_token,"tr$ange")) {
  2022.         (void) putc('\n',stderr);
  2023.         show_range('t',tmin,tmax);
  2024.         c_token++;
  2025.     }
  2026.     else if (almost_equals(c_token,"ur$ange")) {
  2027.         (void) putc('\n',stderr);
  2028.         show_range('u',umin,umax);
  2029.         c_token++;
  2030.     }
  2031.     else if (almost_equals(c_token,"vi$ew")) {
  2032.         (void) putc('\n',stderr);
  2033.         show_view();
  2034.         c_token++;
  2035.     }
  2036.     else if (almost_equals(c_token,"vr$ange")) {
  2037.         (void) putc('\n',stderr);
  2038.         show_range('v',vmin,vmax);
  2039.         c_token++;
  2040.     }
  2041.     else if (almost_equals(c_token,"v$ariables")) {
  2042.         show_variables();
  2043.         c_token++;
  2044.     }
  2045.     else if (almost_equals(c_token,"ve$rsion")) {
  2046.         show_version();
  2047.         c_token++;
  2048.     }
  2049.     else if (almost_equals(c_token,"xr$ange")) {
  2050.         (void) putc('\n',stderr);
  2051.         show_range('x',xmin,xmax);
  2052.         c_token++;
  2053.     }
  2054.     else if (almost_equals(c_token,"yr$ange")) {
  2055.         (void) putc('\n',stderr);
  2056.         show_range('y',ymin,ymax);
  2057.         c_token++;
  2058.     }
  2059.     else if (almost_equals(c_token,"zr$ange")) {
  2060.         (void) putc('\n',stderr);
  2061.         show_range('z',zmin,zmax);
  2062.         c_token++;
  2063.     }
  2064.     else if (almost_equals(c_token,"z$ero")) {
  2065.         (void) putc('\n',stderr);
  2066.         show_zero();
  2067.         c_token++;
  2068.     }
  2069.     else if (almost_equals(c_token,"a$ll")) {
  2070.         c_token++;
  2071.         show_version();
  2072.         show_autoscale();
  2073.         show_border();
  2074.         show_clip();
  2075.         show_contour();
  2076.         show_mapping();
  2077.           (void) fprintf(stderr,"\tdummy variables are \"%s\" and \"%s\"\n",
  2078.                         dummy_var[0], dummy_var[1]);
  2079.         show_format();
  2080.         show_style("data",data_style);
  2081.         show_style("functions",func_style);
  2082.         show_grid();
  2083.         show_label(0);
  2084.         show_arrow(0);
  2085.         show_key();
  2086.         show_logscale();
  2087.         show_offsets();
  2088.         show_output();
  2089.         show_parametric();
  2090.         show_polar();
  2091.         show_angles();
  2092.         show_samples();
  2093.         show_isosamples();
  2094.         show_view();
  2095.         show_surface();
  2096.         show_hidden3d();
  2097.         show_size();
  2098.         show_term();
  2099.         show_tics(TRUE,TRUE,TRUE);
  2100.         show_time();
  2101.         if (parametric)
  2102.             if (!is_3d_plot)
  2103.                 show_range('t',tmin,tmax);
  2104.             else {
  2105.                 show_range('u',umin,umax);
  2106.                 show_range('v',vmin,vmax);
  2107.             }
  2108.         if (polar)
  2109.           show_range('r',rmin,rmax);
  2110.         show_range('x',xmin,xmax);
  2111.         show_range('y',ymin,ymax);
  2112.         show_range('z',zmin,zmax);
  2113.         show_title();
  2114.         show_xlabel();
  2115.         show_ylabel();
  2116.         show_zlabel();
  2117.         show_zero();
  2118.         show_plot();
  2119.         show_variables();
  2120.         show_functions();
  2121.         c_token++;
  2122.     }
  2123.     else
  2124.         return (FALSE);
  2125.     return (TRUE);
  2126. }
  2127.  
  2128.  
  2129. /*********** support functions for 'show'  **********/
  2130. static void
  2131. show_style(name,style)
  2132. char name[];
  2133. enum PLOT_STYLE style;
  2134. {
  2135.     fprintf(stderr,"\t%s are plotted with ",name);
  2136.     switch (style) {
  2137.         case LINES: fprintf(stderr,"lines\n"); break;
  2138.         case POINTS: fprintf(stderr,"points\n"); break;
  2139.         case IMPULSES: fprintf(stderr,"impulses\n"); break;
  2140.         case LINESPOINTS: fprintf(stderr,"linespoints\n"); break;
  2141.         case DOTS: fprintf(stderr,"dots\n"); break;
  2142.         case ERRORBARS: fprintf(stderr,"errorbars\n"); break;
  2143.     }
  2144. }
  2145.  
  2146. static void
  2147. show_range(name,min,max)
  2148. char name;
  2149. double min,max;
  2150. {
  2151.     fprintf(stderr,"\t%crange is [%g : %g]\n",name,min,max);
  2152. }
  2153.  
  2154. static void
  2155. show_zero()
  2156. {
  2157.     fprintf(stderr,"\tzero is %g\n",zero);
  2158. }
  2159.  
  2160. static void
  2161. show_offsets()
  2162. {
  2163.     fprintf(stderr,"\toffsets are %g, %g, %g, %g\n",loff,roff,toff,boff);
  2164. }
  2165.  
  2166. static void
  2167. show_border()
  2168. {
  2169.     fprintf(stderr,"\tborder is %sdrawn\n", draw_border ? "" : "not ");
  2170. }
  2171.  
  2172. static void
  2173. show_output()
  2174. {
  2175.     fprintf(stderr,"\toutput is sent to %s\n",outstr);
  2176. }
  2177.  
  2178. static void
  2179. show_samples()
  2180. {
  2181.     fprintf(stderr,"\tsampling rate is %d\n",samples);
  2182. }
  2183.  
  2184. static void
  2185. show_isosamples()
  2186. {
  2187.     fprintf(stderr,"\tiso sampling rate is %d\n",iso_samples);
  2188. }
  2189.  
  2190. static void
  2191. show_surface()
  2192. {
  2193.     fprintf(stderr,"\tsurface is %sdrawn\n", draw_surface ? "" : "not ");
  2194. }
  2195.  
  2196. static void
  2197. show_hidden3d()
  2198. {
  2199.     fprintf(stderr,"\thidden surface is %s\n", hidden3d ? "removed" : "drawn");
  2200. }
  2201.  
  2202. static void
  2203. show_view()
  2204. {
  2205.     fprintf(stderr,"\tview is %g rot_x, %g rot_z, %g scale, %g scale_z\n",
  2206.         surface_rot_x, surface_rot_z, surface_scale, surface_zscale);
  2207. }
  2208.  
  2209. static void
  2210. show_size()
  2211. {
  2212.     fprintf(stderr,"\tsize is scaled by %g,%g\n",xsize,ysize);
  2213. }
  2214.  
  2215. static void
  2216. show_title()
  2217. {
  2218.     fprintf(stderr,"\ttitle is \"%s\", offset at %d, %d\n",
  2219.         title,title_xoffset,title_yoffset);
  2220. }
  2221.  
  2222. static void
  2223. show_xlabel()
  2224. {
  2225.     fprintf(stderr,"\txlabel is \"%s\", offset at %d, %d\n",
  2226.         xlabel,xlabel_xoffset,xlabel_yoffset);
  2227. }
  2228.  
  2229. static void
  2230. show_ylabel()
  2231. {
  2232.     fprintf(stderr,"\tylabel is \"%s\", offset at %d, %d\n",
  2233.         ylabel,ylabel_xoffset,ylabel_yoffset);
  2234. }
  2235. static void
  2236. show_zlabel()
  2237. {
  2238.     fprintf(stderr,"\tzlabel is \"%s\", offset at %d, %d\n",
  2239.         zlabel,zlabel_xoffset,zlabel_yoffset);
  2240. }
  2241.  
  2242. static void
  2243. show_xzeroaxis()
  2244. {
  2245.     fprintf(stderr,"\txzeroaxis is %s\n",(xzeroaxis)? "ON" : "OFF");
  2246. }
  2247.  
  2248. static void
  2249. show_yzeroaxis()
  2250. {
  2251.     fprintf(stderr,"\tyzeroaxis is %s\n",(yzeroaxis)? "ON" : "OFF");
  2252. }
  2253.  
  2254. static void
  2255. show_label(tag)
  2256.     int tag;                /* 0 means show all */
  2257. {
  2258.     struct text_label *this_label;
  2259.     BOOLEAN showed = FALSE;
  2260.  
  2261.     for (this_label = first_label; this_label != NULL;
  2262.         this_label = this_label->next) {
  2263.        if (tag == 0 || tag == this_label->tag) {
  2264.           showed = TRUE;
  2265.           fprintf(stderr,"\tlabel %d \"%s\" at %g,%g,%g ",
  2266.                 this_label->tag, this_label->text, 
  2267.                 this_label->x, this_label->y, this_label->z);
  2268.           switch(this_label->pos) {
  2269.              case LEFT : {
  2270.                 fprintf(stderr,"left");
  2271.                 break;
  2272.              }
  2273.              case CENTRE : {
  2274.                 fprintf(stderr,"centre");
  2275.                 break;
  2276.              }
  2277.              case RIGHT : {
  2278.                 fprintf(stderr,"right");
  2279.                 break;
  2280.              }
  2281.           }
  2282.           fputc('\n',stderr);
  2283.        }
  2284.     }
  2285.     if (tag > 0 && !showed)
  2286.      int_error("label not found", c_token);
  2287. }
  2288.  
  2289. static void
  2290. show_arrow(tag)
  2291.     int tag;                /* 0 means show all */
  2292. {
  2293.     struct arrow_def *this_arrow;
  2294.     BOOLEAN showed = FALSE;
  2295.  
  2296.     for (this_arrow = first_arrow; this_arrow != NULL;
  2297.         this_arrow = this_arrow->next) {
  2298.        if (tag == 0 || tag == this_arrow->tag) {
  2299.           showed = TRUE;
  2300.           fprintf(stderr,"\tarrow %d from %g,%g,%g to %g,%g,%g%s\n",
  2301.                 this_arrow->tag, 
  2302.                 this_arrow->sx, this_arrow->sy, this_arrow->sz,
  2303.                 this_arrow->ex, this_arrow->ey, this_arrow->ez,
  2304.                 this_arrow->head ? "" : " (nohead)");
  2305.        }
  2306.     }
  2307.     if (tag > 0 && !showed)
  2308.      int_error("arrow not found", c_token);
  2309. }
  2310.  
  2311. static void
  2312. show_grid()
  2313. {
  2314.     fprintf(stderr,"\tgrid is %s\n",(grid)? "ON" : "OFF");
  2315. }
  2316.  
  2317. static void
  2318. show_key()
  2319. {
  2320.     switch (key) {
  2321.         case -1 : 
  2322.             fprintf(stderr,"\tkey is ON\n");
  2323.             break;
  2324.         case 0 :
  2325.             fprintf(stderr,"\tkey is OFF\n");
  2326.             break;
  2327.         case 1 :
  2328.             fprintf(stderr,"\tkey is at %g,%g,%g\n",key_x,key_y,key_z);
  2329.             break;
  2330.     }
  2331. }
  2332.  
  2333. static void
  2334. show_parametric()
  2335. {
  2336.     fprintf(stderr,"\tparametric is %s\n",(parametric)? "ON" : "OFF");
  2337. }
  2338.  
  2339. static void
  2340. show_polar()
  2341. {
  2342.     fprintf(stderr,"\tpolar is %s\n",(polar)? "ON" : "OFF");
  2343. }
  2344.  
  2345. static void
  2346. show_angles()
  2347. {
  2348.     fprintf(stderr,"\tAngles are in ");
  2349.     switch (angles_format) {
  2350.         case ANGLES_RADIANS:
  2351.             fprintf(stderr, "radians\n");
  2352.         break;
  2353.         case ANGLES_DEGREES:
  2354.             fprintf(stderr, "degrees\n");
  2355.         break;
  2356.     }
  2357. }
  2358.  
  2359.  
  2360. static void
  2361. show_tics(showx, showy, showz)
  2362.     BOOLEAN showx, showy, showz;
  2363. {
  2364.     fprintf(stderr,"\ttics are %s, ",(tic_in)? "IN" : "OUT");
  2365.     fprintf(stderr,"\tticslevel is %g\n",ticslevel);
  2366.  
  2367.     if (showx)
  2368.      show_ticdef(xtics, 'x', &xticdef);
  2369.     if (showy)
  2370.      show_ticdef(ytics, 'y', &yticdef);
  2371.     if (showz)
  2372.      show_ticdef(ztics, 'z', &zticdef);
  2373.     screen_ok = FALSE;
  2374. }
  2375.  
  2376. /* called by show_tics */
  2377. static void
  2378. show_ticdef(tics, axis, tdef)
  2379.     BOOLEAN tics;            /* xtics ytics or ztics */
  2380.     char axis;            /* 'x' 'y' or 'z' */
  2381.     struct ticdef *tdef;    /* xticdef yticdef or zticdef */
  2382. {
  2383.     register struct ticmark *t;
  2384.  
  2385.     fprintf(stderr, "\t%c-axis tic labelling is ", axis);
  2386.     if (!tics) {
  2387.        fprintf(stderr, "OFF\n");
  2388.        return;
  2389.     }
  2390.  
  2391.     switch(tdef->type) {
  2392.        case TIC_COMPUTED: {
  2393.           fprintf(stderr, "computed automatically\n");
  2394.           break;
  2395.        }
  2396.        case TIC_SERIES: {
  2397.           if (tdef->def.series.end == VERYLARGE)
  2398.             fprintf(stderr, "series from %g by %g\n", 
  2399.                   tdef->def.series.start, tdef->def.series.incr);
  2400.           else
  2401.             fprintf(stderr, "series from %g by %g until %g\n", 
  2402.                   tdef->def.series.start, tdef->def.series.incr, 
  2403.                   tdef->def.series.end);
  2404.           break;
  2405.        }
  2406.        case TIC_USER: {
  2407.           fprintf(stderr, "list (");
  2408.           for (t = tdef->def.user; t != NULL; t=t->next) {
  2409.              if (t->label)
  2410.                fprintf(stderr, "\"%s\" ", t->label);
  2411.              if (t->next)
  2412.                fprintf(stderr, "%g, ", t->position);
  2413.              else
  2414.                fprintf(stderr, "%g", t->position);
  2415.           }
  2416.           fprintf(stderr, ")\n");
  2417.           break;
  2418.        }
  2419.        default: {
  2420.           int_error("unknown ticdef type in show_ticdef()", NO_CARET);
  2421.           /* NOTREACHED */
  2422.        }
  2423.     }
  2424. }
  2425.  
  2426. static void
  2427. show_time()
  2428. {
  2429.     fprintf(stderr,"\ttime is %s, offset at %d, %d\n",
  2430.         (timedate)? "ON" : "OFF",
  2431.         time_xoffset,time_yoffset);
  2432. }
  2433.  
  2434. static void
  2435. show_term()
  2436. {
  2437.     char *str;
  2438.  
  2439.     fprintf(stderr,"\tterminal type is %s %s\n",
  2440.         term_tbl[term].name, term_options);
  2441. }
  2442.  
  2443. static void
  2444. show_plot()
  2445. {
  2446.     fprintf(stderr,"\tlast plot command was: %s\n",replot_line);
  2447. }
  2448.  
  2449. static void
  2450. show_autoscale()
  2451. {
  2452.     fprintf(stderr,"\tautoscaling is ");
  2453.     if (parametric)
  2454.         if (is_3d_plot)
  2455.             fprintf(stderr,"\tt: %s, ",(autoscale_t)? "ON" : "OFF");
  2456.         else
  2457.             fprintf(stderr,"\tu: %s, v: %s, ",
  2458.                         (autoscale_u)? "ON" : "OFF",
  2459.                         (autoscale_v)? "ON" : "OFF");
  2460.     else fprintf(stderr,"\t");
  2461.  
  2462.     if (polar) fprintf(stderr,"r: %s, ",(autoscale_r)? "ON" : "OFF");
  2463.     fprintf(stderr,"x: %s, ",(autoscale_x)? "ON" : "OFF");
  2464.     fprintf(stderr,"y: %s, ",(autoscale_y)? "ON" : "OFF");
  2465.     fprintf(stderr,"z: %s\n",(autoscale_z)? "ON" : "OFF");
  2466. }
  2467.  
  2468. static void
  2469. show_clip()
  2470. {
  2471.     fprintf(stderr,"\tpoint clip is %s\n",(clip_points)? "ON" : "OFF");
  2472.  
  2473.     if (clip_lines1)
  2474.       fprintf(stderr,
  2475.          "\tdrawing and clipping lines between inrange and outrange points\n");
  2476.     else
  2477.       fprintf(stderr,
  2478.          "\tnot drawing lines between inrange and outrange points\n");
  2479.  
  2480.     if (clip_lines2)
  2481.       fprintf(stderr,
  2482.          "\tdrawing and clipping lines between two outrange points\n");
  2483.     else
  2484.       fprintf(stderr,
  2485.          "\tnot drawing lines between two outrange points\n");
  2486. }
  2487.  
  2488. static void
  2489. show_mapping()
  2490. {
  2491.     fprintf(stderr,"\tmapping for 3-d data is ");
  2492.  
  2493.     switch (mapping3d) {
  2494.         case MAP3D_CARTESIAN:
  2495.             fprintf(stderr,"cartesian\n");
  2496.             break;
  2497.         case MAP3D_SPHERICAL:
  2498.             fprintf(stderr,"spherical\n");
  2499.             break;
  2500.         case MAP3D_CYLINDRICAL:
  2501.             fprintf(stderr,"cylindrical\n");
  2502.             break;
  2503.     }
  2504. }
  2505.  
  2506. static void
  2507. show_contour()
  2508. {
  2509.     fprintf(stderr,"\tcontour for surfaces are %s",
  2510.         (draw_contour)? "drawn" : "not drawn\n");
  2511.  
  2512.     if (draw_contour) {
  2513.             fprintf(stderr, " in %d levels on ", contour_levels);
  2514.         switch (draw_contour) {
  2515.             case CONTOUR_BASE:
  2516.                 fprintf(stderr,"grid base\n");
  2517.                 break;
  2518.             case CONTOUR_SRF:
  2519.                 fprintf(stderr,"surface\n");
  2520.                 break;
  2521.             case CONTOUR_BOTH:
  2522.                 fprintf(stderr,"grid base and surface\n");
  2523.                 break;
  2524.         }
  2525.         switch (contour_kind) {
  2526.             case CONTOUR_KIND_LINEAR:
  2527.                 fprintf(stderr,"\t\tas linear segments\n");
  2528.                 break;
  2529.             case CONTOUR_KIND_CUBIC_SPL:
  2530.                 fprintf(stderr,"\t\tas cubic spline interpolation segments with %d pts\n",
  2531.                     contour_pts);
  2532.                 break;
  2533.             case CONTOUR_KIND_BSPLINE:
  2534.                 fprintf(stderr,"\t\tas bspline approximation segments of order %d with %d pts\n",
  2535.                     contour_order, contour_pts);
  2536.                 break;
  2537.         }
  2538.     }
  2539. }
  2540.  
  2541. static void
  2542. show_format()
  2543. {
  2544.     fprintf(stderr, "\ttic format is x-axis: \"%s\", y-axis: \"%s\", z-axis: \"%s\"\n",
  2545.         xformat, yformat, zformat);
  2546. }
  2547.  
  2548. static void
  2549. show_logscale()
  2550. {
  2551.     char *p;
  2552.  
  2553.     if (log_x && log_y && log_z)
  2554.         fprintf(stderr,"\tlogscaling all x, y and z axes\n");
  2555.     else {
  2556.         p = (log_x && log_y)              /* Look for pairs. */
  2557.              ? "x and y"
  2558.              :  (log_x && log_z)
  2559.                      ? "x and z"
  2560.                      :  (log_y && log_z)
  2561.                      ? "y and z"
  2562.                      : NULL;
  2563.         if (p != NULL)
  2564.             fprintf(stderr,"\tlogscaling both %s axes\n",p);
  2565.         else {
  2566.             if (log_x)
  2567.                 fprintf(stderr,"\tlogscaling x axis\n");
  2568.             if (log_y)
  2569.                 fprintf(stderr,"\tlogscaling y axis\n");
  2570.             if (log_z)
  2571.                 fprintf(stderr,"\tlogscaling z axis\n");
  2572.             if (!(log_x || log_y || log_z))
  2573.                 fprintf(stderr,"\tno logscaling\n");
  2574.         }
  2575.     }
  2576. }
  2577.  
  2578. static void
  2579. show_variables()
  2580. {
  2581. register struct udvt_entry *udv = first_udv;
  2582. int len;
  2583.  
  2584.     fprintf(stderr,"\n\tVariables:\n");
  2585.     while (udv) {
  2586.          len = instring(udv->udv_name, ' ');
  2587.         fprintf(stderr,"\t%-*s ",len,udv->udv_name);
  2588.         if (udv->udv_undef)
  2589.             fputs("is undefined\n",stderr);
  2590.         else {
  2591.             fputs("= ",stderr);
  2592.             disp_value(stderr,&(udv->udv_value));
  2593.             (void) putc('\n',stderr);
  2594.         }
  2595.         udv = udv->next_udv;
  2596.     }
  2597. }
  2598.  
  2599. void                /* used by plot.c */
  2600. show_version()
  2601. {
  2602. extern char version[];
  2603. extern char patchlevel[];
  2604. extern char date[];
  2605. extern char bug_email[];
  2606. static char *authors[] = {"Thomas Williams","Colin Kelley"}; /* primary */
  2607. int x;
  2608. long time();
  2609.  
  2610.     x = time((long *)NULL) & 1;
  2611.     fprintf(stderr,"\n\t%s\n\t%sversion %s\n",
  2612.         PROGRAM, OS, version); 
  2613.     fprintf(stderr,"\tpatchlevel %s\n",patchlevel);
  2614.      fprintf(stderr, "\tlast modified %s\n", date);
  2615.     fprintf(stderr,"\nCopyright(C) 1986, 1987, 1990, 1991, 1992  %s, %s\n",
  2616.         authors[x],authors[1-x]);
  2617.     fprintf(stderr, "\n\tSend bugs and comments to %s\n", bug_email);
  2618. }
  2619.